#!/usr/bin/env python
# -*- coding:utf-8 -*-

# file:monitor_plot.py
# author:吴凯博
# datetime:2022/5/2 18:28
# software: PyCharm
"""
this is function description
"""
from matplotlib import pyplot

from config.settings import Settings
from utils.monitor import Monitor

timer = None


def create_figures(data: dict, monitor: Monitor):
    global timer
    if timer is not None:
        return pyplot.figure(1), pyplot.figure(2), pyplot.figure(3)

    net_plot_num = len(data['net_data'])
    x_range = [(x * Settings.DATA_INTERVAL / 1000) for x in range(Settings.DATA_POINTS).__reversed__()]

    cpu_fig, cpu_ax = pyplot.subplots(num=1, clear=True)
    memory_fig, memory_axes = pyplot.subplots(num=2, ncols=2, clear=True)
    net_fig, net_axes = pyplot.subplots(num=3, ncols=net_plot_num, clear=True)

    if not isinstance(net_axes, type(memory_axes)):
        # 因pyplot.subplots创建ax对象时，根据ncols参数的数值会返回不同的数据类型
        # 当ncols为1时返回一个ax类的对象，大于1时返回一个列表
        # 于是这里统一将返回值设为列表，避免出错
        net_axes = [net_axes]

    # 初始化CPU利用率图
    cpu_ax.set_ylim([0, 100])  # 固定y轴
    cpu_ax.set_xlim([Settings.DATA_POINTS * Settings.DATA_INTERVAL / 1000, 0])  # 固定x轴
    cpu_ax.set_autoscale_on(False)  # 自动缩放关
    cpu_ax.plot(x_range, data['cpu_data']['cpu_percent'], label='CPU use rate')  # 画CPU利用率折线
    cpu_ax.legend()  # 设置图例
    cpu_ax.set_title('CPU use rate')  # 标题
    cpu_ax.set_xlabel('time (s)')  # x轴标签
    cpu_ax.set_ylabel('rate (%)')  # y轴标签

    # 初始化内存利用率/利用详情图
    # memory_axes[0]为利用率图/memory_axes[1]为利用详情图
    memory_axes[0].set_ylim([0, 100])
    memory_axes[0].set_xlim([Settings.DATA_POINTS * Settings.DATA_INTERVAL / 1000, 0])
    memory_axes[0].set_autoscale_on(False)
    memory_axes[0].plot(x_range, data['memory_data']['memory_percent'], label='memory use rate')
    memory_axes[0].legend()
    memory_axes[0].set_title('memory use rate')
    memory_axes[0].set_xlabel('time (s)')
    memory_axes[0].set_ylabel('rate (%)')
    memory_axes[1].set_ylim([0, int(data['memory_data']['total'] + 1)])
    memory_axes[1].set_xlim([Settings.DATA_POINTS * Settings.DATA_INTERVAL / 1000, 0])
    memory_axes[1].set_autoscale_on(False)
    memory_axes[1].plot(x_range, data['memory_data']['memory_free'], 'g-', label='free memory')
    memory_axes[1].plot(x_range, data['memory_data']['memory_used'], 'r-', label='used memory')
    memory_axes[1].legend()
    memory_axes[1].set_title('used/free memory')
    memory_axes[1].set_xlabel('time (s)')
    memory_axes[1].set_ylabel('memory capacity (GB)')

    # 初始化网络使用情况
    # net_axes中的元素为已启用的各网卡的使用详情
    net_ax_index = 0
    for net_name in data['net_data'].keys():
        net_axes[net_ax_index].set_ylim([0, 100])
        net_axes[net_ax_index].set_xlim([Settings.DATA_POINTS * Settings.DATA_INTERVAL / 1000, 0])
        net_axes[net_ax_index].set_autoscale_on(False)
        net_axes[net_ax_index].plot(x_range, data['net_data'][net_name]['bytes_recv'], 'g-', label='receive')
        net_axes[net_ax_index].plot(x_range, data['net_data'][net_name]['bytes_sent'], 'r-', label='sent')
        net_axes[net_ax_index].legend()
        net_axes[net_ax_index].set_title(net_name)
        net_axes[net_ax_index].set_xlabel('time (s)')
        net_axes[net_ax_index].set_ylabel('bytes (B)')
        net_ax_index += 1

    timer = cpu_fig.canvas.new_timer(interval=Settings.DATA_INTERVAL)
    timer.add_callback(on_timer, monitor, cpu_ax, memory_axes, net_axes)
    timer.start()

    pyplot.show()


def update_cpu_figure(cpu_ax, data: dict):
    cpu_ax.lines[0].set_ydata(data['cpu_data']['cpu_percent'])
    while True:
        try:
            cpu_ax.draw_artist(cpu_ax.lines[0])
            break
        except Exception as e:
            print(e)
    cpu_ax.figure.canvas.draw()


def update_memory_figure(memory_axes, data: dict):
    memory_axes[0].lines[0].set_ydata(data['memory_data']['memory_percent'])
    memory_axes[1].lines[0].set_ydata(data['memory_data']['memory_free'])
    memory_axes[1].lines[1].set_ydata(data['memory_data']['memory_used'])
    while True:
        try:
            memory_axes[0].draw_artist(memory_axes[0].lines[0])
            memory_axes[0].draw_artist(memory_axes[1].lines[0])
            memory_axes[0].draw_artist(memory_axes[1].lines[1])
            break
        except Exception as e:
            print(e)
    memory_axes[0].figure.canvas.draw()


def update_net_figure(net_axes, data: dict):
    net_ax_index = 0
    for net_name in data['net_data'].keys():
        net_axes[net_ax_index].set_ylim([0, max(
            [1] + [x for x in data['net_data'][net_name]['bytes_recv'] + data['net_data'][net_name]['bytes_sent'] if x]
        )])
        net_axes[net_ax_index].lines[0].set_ydata(data['net_data'][net_name]['bytes_recv'])
        net_axes[net_ax_index].lines[1].set_ydata(data['net_data'][net_name]['bytes_sent'])
        while True:
            try:
                net_axes[net_ax_index].draw_artist(net_axes[net_ax_index].lines[0])
                net_axes[net_ax_index].draw_artist(net_axes[net_ax_index].lines[1])
                break
            except Exception as e:
                print(e)
        net_ax_index += 1
    net_axes[0].figure.canvas.draw()


def on_timer(monitor: Monitor, cpu_ax, memory_axes, net_axes):
    data = monitor.record_data()
    update_cpu_figure(cpu_ax, data)
    update_memory_figure(memory_axes, data)
    update_net_figure(net_axes, data)


def stop_monitor(monitor: Monitor):
    global timer
    if timer is None:
        return
    else:
        timer.stop()
        timer = None
        monitor.init_data()


if __name__ == '__main__':
    _monitor = Monitor()
    _data = _monitor.get_data()
    create_figures(_data, _monitor)
